﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net;
using System.Windows.Threading;
using System.ComponentModel;
using System.Collections.ObjectModel;
using Microsoft.Win32;

namespace VLCMultyRemote
{
    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private ObservableCollection<Client> clients;

        /// <summary>
        /// property for the list of clients, is needed for binding to the dadagrid
        /// and for sending and recieving messages
        /// </summary>
        public ObservableCollection<Client> Clients
        {
            get { return clients; }
            set { clients = value; }
        }

        /// <summary>
        /// initialize the gui, default clients and bindings
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();

            clients = getDefaultClients();
            this.DataContext = clients;

            foreach (Client client in clients)
            {
                client.PropertyChanged += new PropertyChangedEventHandler(client_PropertyChanged);
            }
        }

        void client_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            Client clientSender = (Client)sender;

            if (e.PropertyName == "Status" && clientSender.CanControl)
            {
                Dispatcher.Invoke(new DispatcherOperationCallback(delegate
                {
                    switch (clientSender.Status)
                    {
                        case ("Play"):
                            foreach (Client client in clients)
                            {
                                if (client.Equals(clientSender))
                                    continue;
                                else if (client.Status == "End")
                                {
                                    writeToRichTextBox("Out (" + client.IpAddress + "): " + "play\n");
                                    client.sendCommand("play\n");
                                }
                                else if (client.Status == "Pause")
                                {
                                    writeToRichTextBox("Out (" + client.IpAddress + "): " + "pause\n");
                                    client.sendCommand("pause\n");
                                }
                            }
                            break;
                        case ("Pause"):
                            sendToAllExceptOneClientAndStatus(clientSender, clientSender.Status, "pause\n");
                            break;
                        case ("End"):
                            sendToAllExceptOneClientAndStatus(clientSender, clientSender.Status, "stop\n");
                            break;
                    }
                    return null;
                }), new object[] { null });
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns>a list of default clients</returns>
        private ObservableCollection<Client> getDefaultClients()
        {
            ObservableCollection<Client> tempList = new ObservableCollection<Client>();

            
            Client client1 = new Client(new IPEndPoint(new IPAddress(new Byte[] { 127, 0, 0, 1 }), 9999), "Myself");
            tempList.Add(client1);
            

            /*
            //vm
            Client client2 = new Client(new IPEndPoint(new IPAddress(new Byte[] {192, 168, 178, 28 }), 9999), "vm");
            tempList.Add(client2);
            */

            /*
            Client client3 = new Client(new IPEndPoint(new IPAddress(new Byte[]  5, 82, 156, 128 }), 9999),null);
            tempList.Add(client2);
            */

            return tempList;
        }

        /// <summary>
        /// is called if a client change his status
        /// called from an other thread the gui
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="message"></param>
        void com_OnStatusChanged(object sender, string message)
        {
            Dispatcher.Invoke(new DispatcherOperationCallback(delegate
            {
                writeToRichTextBox("Status: " + message);
                return null;
            }), new object[] { null });

        }

        /// <summary>
        /// is callled if a client recieve a message
        /// called from an other thread the gui
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="message"></param>
        void com_OnDataRecievingControl(object sender, string message)
        {
            Dispatcher.Invoke(new DispatcherOperationCallback(delegate
            {
                writeToRichTextBox("In (" + ((Client)sender).IpAddress + "): " + message + "\n");
                return null;
            }), new object[] { null });
        }

        /// <summary>
        /// sends a message to all clients except one
        /// set excepted null to send to all
        /// </summary>
        /// <param name="excepted"></param>
        /// <param name="command"></param>
        private void sendToAllExceptOneClientAndStatus(object excepted, string exceptedStatus, string command)
        {
            foreach (Client client in clients)
            {
                if (client.Connected && !client.Equals(excepted) && client.Status != exceptedStatus)
                {
                    writeToRichTextBox("Out (" + client.IpAddress + "): " + command);
                    switch (command)
                    {
                        case ("play\n"):
                            client.Status = "Play";
                            break;
                        case ("pause\n"):
                            client.Status = "Pause";
                            break;
                        case ("stop\n"):
                            client.Status = "End";
                            break;
                    }
                    client.sendCommand(command);
                }
            }
        }


        /// <summary>
        /// stops all clien connections in case of closing
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Closing(object sender, CancelEventArgs e)
        {
            foreach (Client client in clients)
            {
                client.stopConnection();
            }
        }

        #region tab console

        /// <summary>
        /// waits for return and sends commands to all clients
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void textBoxCommandInput_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Return && clients.Count != 0)
            {
                sendToAllExceptOneClientAndStatus(null, null, textBoxCommandInput.Text + "\n");

                textBoxCommandInput.Clear();
            }
        }

        /// <summary>
        /// add message to richtextbox
        /// </summary>
        /// <param name="message"></param>
        private void writeToRichTextBox(string message)
        {
            richTextBoxOutput.AppendText(message);

            if (richTextBoxOutput.Document.Blocks.Count >= 250)
                richTextBoxOutput.Document.Blocks.Clear();
            else
                richTextBoxOutput.ScrollToEnd();
        }

        #endregion

        #region tab controls

        private void buttonPlay_Click(object sender, RoutedEventArgs e)
        {
            sendToAllExceptOneClientAndStatus(null, null, "play\n");
        }

        private void buttonPause_Click(object sender, RoutedEventArgs e)
        {
            sendToAllExceptOneClientAndStatus(null, null, "pause\n");
        }

        private void buttonStop_Click(object sender, RoutedEventArgs e)
        {
            sendToAllExceptOneClientAndStatus(null, null, "stop\n");
        }

        private void buttonPrevious_Click(object sender, RoutedEventArgs e)
        {
            sendToAllExceptOneClientAndStatus(null, null, "prev\n");
        }

        private void buttonNext_Click(object sender, RoutedEventArgs e)
        {
            sendToAllExceptOneClientAndStatus(null, null, "next\n");
        }

        private void buttonSlower_Click(object sender, RoutedEventArgs e)
        {
            sendToAllExceptOneClientAndStatus(null, null, "slower\n");
        }

        private void buttonFaster_Click(object sender, RoutedEventArgs e)
        {
            sendToAllExceptOneClientAndStatus(null, null, "faster\n");
        }

        private void buttonAdd_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();

            System.Nullable<Boolean> isOK = openFileDialog.ShowDialog();

            if (isOK == true)
            {
                sendToAllExceptOneClientAndStatus(null, null, "add " + openFileDialog.FileName + "\n");
            }
        }

        /// <summary>
        /// waits for return and seek all clients to given second
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void textBoxSeek_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Return && clients.Count != 0)
            {
                try
                {
                    int seekSecond = int.Parse(textBoxSeek.Text);
                    sendToAllExceptOneClientAndStatus(null, null, "seek " + seekSecond + "\n");
                }
                catch (Exception)
                {
                    MessageBox.Show("Input not valid.");
                }

                textBoxSeek.Clear();
            }
        }

        #endregion

        #region tab clients

        /// <summary>
        /// connect all clients and register eventhandler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonConnectAll_Click(object sender, RoutedEventArgs e)
        {
            writeToRichTextBox("Connect all\n");

            foreach (Client client in clients)
            {
                if (client.Connected)
                    continue;

                client.OnDataRecievingControl += new Client.MessageRecievingEventHandler(com_OnDataRecievingControl);
                client.OnStatusChanged += new Client.MessageRecievingEventHandler(com_OnStatusChanged);
                client.startConnection();
            }
        }

        /// <summary>
        /// dissconnect all clients and deregister al evenhandler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonDisconnectAll_Click(object sender, RoutedEventArgs e)
        {
            writeToRichTextBox("Disconnect all\n");

            foreach (Client client in clients)
            {
                client.stopConnection();
                client.OnDataRecievingControl -= new Client.MessageRecievingEventHandler(com_OnDataRecievingControl);
                client.OnStatusChanged -= new Client.MessageRecievingEventHandler(com_OnStatusChanged);
            }
            //connections.RemoveRange(0, connections.Count);

        }

        /// <summary>
        /// open new window to add a new client
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonAddClient_Click(object sender, RoutedEventArgs e)
        {
            foreach (Client client in clients)
            {
                client.PropertyChanged -= new PropertyChangedEventHandler(client_PropertyChanged);
            }

            AddClientWindow addClientWin = new AddClientWindow(clients);
            addClientWin.Show();
            addClientWin.Closed += new EventHandler(addClientWin_Closed);
        }

        void addClientWin_Closed(object sender, EventArgs e)
        {
            foreach (Client client in clients)
            { 
                client.PropertyChanged +=new PropertyChangedEventHandler(client_PropertyChanged);
            }
        }

        private void buttonGetTitle_Click(object sender, RoutedEventArgs e)
        {
            sendToAllExceptOneClientAndStatus(null, null, "get_title\n");
        }

        /// <summary>
        /// removes the selected client from datagrid
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonRemoveClient_Click(object sender, RoutedEventArgs e)
        {
            if (dataGridClients.SelectedIndex != -1)
            {
                DataGridRow row = (DataGridRow)dataGridClients.ItemContainerGenerator.ContainerFromIndex(dataGridClients.SelectedIndex);
                TextBlock cellContent = dataGridClients.Columns[1].GetCellContent(row) as TextBlock;

                Client clientToRemove = null;

                foreach (Client client in clients)
                {
                    if (client.IpAddress.ToString() == cellContent.Text)
                    {
                        clientToRemove = client;
                        break;
                    }
                }

                if (clientToRemove != null)
                {
                    clientToRemove.stopConnection();
                    clients.Remove(clientToRemove);
                }
            }
        }

        #endregion

    }
}
